#include "um_basic_types.h"
#include "umapi_libc.h"
#include "umUfd.h"
#include "umapi_os.h"
#include "lstack.h"

typedef struct
{
	UM_EFD efd;
	struct umapi_list_head head;
}UM_PRI_EFD;

#define USE_STACK 1
#if USE_STACK
static lstack_t mlstack;
#else
static struct umapi_list_head mFreeUfds;
static UM_HANDLE mutexhandle;
#endif
static UM_PRI_EFD * mEfdBlocks;
static UM_BOOL mInit = UM_FALSE;

#define MAXEFDCOUNT 40960

UM_VOID um_ufd_init()
{	
	if(mInit)
	{
		return ;
	}
#if USE_STACK
	lstack_init(&mlstack, MAXEFDCOUNT);
#else
	umapi_os_mutex_create(UM_NULL, UM_OS_MUTEX_ATTR_RECURSIVE_NP, &mutexhandle);
	umapi_list_create(&mFreeUfds);
#endif

	mEfdBlocks = umapi_malloc(MAXEFDCOUNT * sizeof(UM_PRI_EFD));
	umapi_memset(mEfdBlocks, 0, MAXEFDCOUNT * sizeof(UM_PRI_EFD));
	UM_S32 i;
#if USE_STACK
#else
	umapi_os_mutex_lock(mutexhandle,  -1);
#endif	
	for(i =0 ;i < MAXEFDCOUNT; i++)
	{
		UM_PRI_EFD * pNode = &mEfdBlocks[i];
		pNode->efd.isReading = getReadFlag;
		pNode->efd.setReadFlag = setReadFlag;
		pNode->efd.sendCount = pNode->efd.readCount = 0;
#if USE_STACK	
		lstack_push(&mlstack, pNode);
#else
		umapi_list_add(&pNode->head, &mFreeUfds);
#endif
	}
#if USE_STACK
#else	
	umapi_os_mutex_unlock(mutexhandle);
#endif
	mInit = UM_TRUE;
}
static UM_EFD* __getFreeNode()
{
	UM_PRI_EFD* pEfd = UM_NULL;
#if USE_STACK
	pEfd = lstack_pop(&mlstack);
	if(pEfd)
		pEfd->efd.active = UM_TRUE;	
#else	
	struct umapi_list_head *pos, *n;
	umapi_os_mutex_lock(mutexhandle,  -1);
	umapi_list_for_each_safe(pos, n, &mFreeUfds)
	{
		pEfd = umapi_list_entry(pos, UM_PRI_EFD, head);
		umapi_list_del(&pEfd->head);
		pEfd->efd.active = UM_TRUE;
		break;
	}
	umapi_os_mutex_unlock(mutexhandle);
#endif	
	return (UM_EFD*)pEfd;
}
static UM_VOID __freeUfd(UM_PRI_EFD * pEfd)
{
	pEfd->efd.active = UM_FALSE;
#if USE_STACK
	lstack_push(&mlstack, pEfd);
#else
	umapi_os_mutex_lock(mutexhandle,  -1);
	umapi_list_add(&pEfd->head, &mFreeUfds);
	umapi_os_mutex_unlock(mutexhandle);
#endif	
}
UM_EFD* um_ufd_malloc(UM_HANDLE fd,
	UM_S32 (*conntect)(UM_HANDLE fd, UM_VOID* param,UM_VOID *efd),
	UM_S32 (*read)(UM_HANDLE fd, UM_VOID* param),
	UM_S32 (*disconnect)(UM_HANDLE fd, UM_VOID* param),
	UM_U32 status,
	UM_VOID *pri)
{
	UM_EFD *ret = __getFreeNode();
	if(!ret)
		return UM_NULL;
	ret->fd = fd;
	ret->conntect = conntect;
	ret->read = read;
	ret->disconnect = disconnect;
	ret->status = status;
	ret->write = UM_NULL;
	ret->lasttick = umapi_os_get_tick();
	ret->pri = pri;
	ret->sendCount = ret->readCount = 0;
	return ret;
}

UM_VOID um_ufd_free(UM_VOID **pfd)
{
	if(!*pfd)
		return ;
	UM_EFD *ufd = *(UM_EFD **)pfd;
	umapi_socket_close(ufd->fd);
	__freeUfd((UM_PRI_EFD *)ufd);
	*pfd = UM_NULL;
	return ;
}

UM_VOID um_ufd_setWriteFunction(UM_HANDLE fd, 
	UM_S32 (*write)(UM_HANDLE fd, UM_VOID* param),
	UM_VOID *param)
{
	UM_EFD *ufd = (UM_EFD *)fd;
	ufd->pri1 = param;
	ufd->write = write;
	listenWriteEvent(ufd);
}


